/*! \file
 *      \brief The first user program - 
 *             the test case follows the structure of the producer consumer 
 *             example in Tanenbaum's book.
 *
 */

#include <scwrapper.h>

long buffer[16];
int head = 0;
int tail = 0;

long empty_semaphore_handle;
long mutex_semaphore_handle;
long full_semaphore_handle;


#define INT_STRINGIFY(x)	#x
#define INT_TOSTRING(x)		INT_STRINGIFY(x)
#define FILE_AND_LINE		__FILE__ ":" INT_TOSTRING(__LINE__)	


void thread(void) {
	/* This is the consumer. */

	while (1) {
		long value;

		if (ALL_OK != semaphoredown(full_semaphore_handle)) {
			prints("T0_full_down: semaphoredown failed!\n");
			break;
		}

		if (ALL_OK != semaphoredown(mutex_semaphore_handle)) {
			prints("T1_mutex_down: semaphoredown failed!\n");
			break;
		}

		value = buffer[tail];
		tail = (tail + 1)&15;

		if (ALL_OK != semaphoreup(mutex_semaphore_handle)) {
			prints("T2_mutex_up: semaphoreup failed!\n");
			break;
		}

		if (ALL_OK != semaphoreup(empty_semaphore_handle)) {
			prints("T3_empty_up: semaphoreup failed!\n");
			break;
		}

		printhex(value);
		prints("\n");
	}
	terminate();
}

void
main(int argc, char* argv[]) {
	register long counter = 0;
	register long thread_stack;

	
	empty_semaphore_handle = createsemaphore(16);
	if (empty_semaphore_handle < 0) {
		prints("createsemaphore failed!\n");
		return;
	}

	full_semaphore_handle = createsemaphore(0);
	if (full_semaphore_handle < 0) {
		prints("createsemaphore failed!\n");
		return;
	}

	mutex_semaphore_handle = createsemaphore(1);
	if (mutex_semaphore_handle < 0) {
		prints("createsemaphore failed!\n");
		return;
	}

	thread_stack = alloc(4096, 0);

	if (0 >= thread_stack) {
		prints("Could not allocate the thread's stack!\n");
		return;
	}

	if (ALL_OK != createthread(thread, thread_stack + 4096)) {
		prints("createthread failed!\n");
		return;
	}

	/* This is the producer. */
	while (1) {
		if (ALL_OK != semaphoredown(empty_semaphore_handle)) {
			prints("M0_empty_down: semaphoredown failed!\n");
			break;
		}

		if (ALL_OK != semaphoredown(mutex_semaphore_handle)) {
			prints("M1_mutex_down: semaphoredown failed!\n");
			break;
		}

		buffer[head] = counter++;
		head = (head + 1)&15;

		if (ALL_OK != semaphoreup(mutex_semaphore_handle)) {
			prints("M2_mutex_up: semaphoreup failed!\n");
			break;
		}

		if (ALL_OK != semaphoreup(full_semaphore_handle)) {
			prints("M3_full_up: semaphoreup failed!\n");
			break;
		}
	}
}
